package org.scratchcrew.services;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

/**
 * Implementation of the {@link DigestSupport} strategy interface.
 */
public class DigestSupportImpl implements DigestSupport {
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	private String algorithm;
	private String charsetName;
	private MessageDigest messageDigest;
	private DigestToTextSupport digestToTextStrategy;

	@Required
	public void setAlgorithm(String algorithm) {
		this.algorithm = algorithm;
	}

	public void setCharset(String charset) {
		this.charsetName = charset;
	}

	public void setDigestToTextStrategy(DigestToTextSupport digestToTextStrategy) {
		this.digestToTextStrategy = digestToTextStrategy;
	}

	@PostConstruct
	public void init() throws NoSuchAlgorithmException {
		if (logger.isTraceEnabled()) {
			logger.trace(String.format("Initializing digest support"
					+ " for algorithm %s", algorithm));
		}
		messageDigest = MessageDigest.getInstance(algorithm);
	}

	@Override
	public String digestToText(String message) {
		Charset charsetToUse = lookupCharset();
		if (logger.isTraceEnabled()) {
			logger.trace(String.format("Digesting message '%s'.", message));
		}
		byte[] messageBytes = message.getBytes(charsetToUse);
		byte[] digest = messageDigest.digest(messageBytes);
		String result;
		if (null == this.digestToTextStrategy) {
			result = digestToText(digest, charsetToUse);
		} else {
			result = this.digestToTextStrategy.toText(digest, charsetToUse);
		}
		return result;
	}

	private Charset lookupCharset() {
		if (logger.isDebugEnabled()) {
			logger.debug(String.format("Looking up for charset '%s'.",
					charsetName));
		}
		Charset charset;
		if (charsetName != null && Charset.isSupported(charsetName)) {
			charset = Charset.forName(this.charsetName);
		} else {
			charset = Charset.defaultCharset();
		}
		return charset;
	}

	private static String digestToText(byte[] digest, Charset charsetToUse) {
		return new String(digest, charsetToUse);
	}

}
